﻿using Afterbunny.Windows.Helpers;
using DistributedVisionRunner.Interface;
using DistributedVisionRunner.Interface.Model;
using DistributedVisionRunner.Module.ChangeTracking;
using DistributedVisionRunner.Module.Helper;
using Prism.Commands;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Input;
using System.Xml.Serialization;

namespace DistributedVisionRunner.Module.ViewModels
{
    public class BoundaryCollectionViewModel
    {
        public OutputDataType DataType { get; }

        public List<BoundaryItem> BoundaryItems { get; }

        public ICommand ShowChangeHistoriesCommand { get; }

        private readonly List<BoundaryItem> _copies;

        private List<Commit> _commits;

        private readonly string _unitName;

        public BoundaryCollectionViewModel(OutputDataType dataType, List<BoundaryItem> boundaryItems, string unitName, IDialogService dialogService)
        {
            DataType = dataType;
            BoundaryItems = boundaryItems;
            _unitName = unitName;

            ShowChangeHistoriesCommand = new DelegateCommand(() =>
            {
                if (_commits.Any())
                {
                    var reverseCommits = new List<Commit>(_commits);
                    reverseCommits.Reverse();
                    dialogService.ShowDialog("CommitViewerDialog",
                        new DialogParameters() { { "Commits", reverseCommits } }, r => { });
                }
            });

            CopyBoundaries(BoundaryItems, ref _copies);

            // Load change histories
            var dir = Path.Combine(Constants.AppDataDir, $"{_unitName}/Changes");
            Directory.CreateDirectory(dir);
            var changeHistoryFilePath = Path.Combine(dir, $"boundaries-{dataType}.xml");
            if (!File.Exists(changeHistoryFilePath))
            {
                _commits = new List<Commit>();
            }
            else

            {
                using (var reader = new StreamReader(changeHistoryFilePath))
                {
                    var serializer = new XmlSerializer(typeof(List<Commit>));
                    _commits = serializer.Deserialize(reader) as List<Commit>;

                }
            }
        }

        private void CopyBoundaries(List<BoundaryItem> original, ref List<BoundaryItem> copy)
        {
            if (original == null) return;

            copy = new List<BoundaryItem>();

            foreach (var boundaryItem in original)
            {
                copy.Add(MiscHelper.CopyObject(boundaryItem));
            }
        }

        public void Save()
        {
            // Save configs
            Helpers.SaveBoundaries(_unitName, DataType, BoundaryItems);

            // Save change history
            {
                List<Change> CompareSimpleProps(BoundaryItem unchanged, BoundaryItem edited)
                {
                    var currentChanges = new List<Change>();

                    string GetChangeName(string prop, string fai)
                    {
                        return $"{fai}[{prop}]";
                    }

                    if (unchanged.Enable != edited.Enable) currentChanges.Add(new Change() { Name = GetChangeName("启用", unchanged.Name), OldValue = unchanged.Enable, NewValue = edited.Enable });
                    if (Math.Abs(unchanged.Ceiling - edited.Ceiling) > double.Epsilon) currentChanges.Add(new Change() { Name = GetChangeName("上限", unchanged.Name), OldValue = unchanged.Ceiling, NewValue = edited.Ceiling });
                    if (Math.Abs(unchanged.Floor - edited.Floor) > double.Epsilon) currentChanges.Add(new Change() { Name = GetChangeName("下限", unchanged.Name), OldValue = unchanged.Floor, NewValue = edited.Floor });

                    return currentChanges;
                }

                var changes = new List<Change>();
                // Compare for changes
                for (int itemIndex = 0; itemIndex < BoundaryItems.Count; itemIndex++)
                {
                    var edited = BoundaryItems[itemIndex];
                    var unchanged = _copies[itemIndex];
                    var changesForItem = CompareSimpleProps(unchanged, edited);
                    if (changesForItem.Any())
                    {
                        changes.AddRange(changesForItem);
                    }
                }

                if (changes.Any())
                {
                    _commits.Add(new Commit() { Changes = changes, Time = DateTime.Now });

                    if (_commits.Count > 50) _commits = _commits.Skip(10).ToList();

                    var dir = Path.Combine(Constants.AppDataDir, $"{_unitName}/Changes");
                    Directory.CreateDirectory(dir);
                    var changeHistoryFilePath = Path.Combine(dir, $"boundaries-{DataType}.xml");
                    using (var writer = new StreamWriter(changeHistoryFilePath))
                    {
                        var serializer = new XmlSerializer(typeof(List<Commit>));
                        serializer.Serialize(writer, _commits);
                    }
                }


            }
        }

    }
}